#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <err.h>
#include <libmscommon/mscommon.h>
#include <libmscommon/msnetwork.h>
#include <libmscommon/msepoll.h>
#include <libmscommon/mstime.h>
#include <libmscommon/msmd.h>
#include <libmscommon/msenv.h>
#include <libmscommon/msmem.h>
#include <libmslog/mslog.h>
#include <libmsprotocol/msprotocol.h>

#define FLAG "PTL_UTM"

#define mshostname_ipaddr	"192.168.200.244"
#define mshostname_port	50000
#define mshostname_url_http	"http://127.0.0.1:8010/ch31.ts"
#define mshostname_url_rtsp	"rtsp://127.0.0.1:8010/ch31.ts"

typedef enum{
	TESTMODE_HTTP=0x00,
	TESTMODE_RTSPPULL_OVER_UDP,	
	TESTMODE_RTSP_OVER_TCP,
	TESTMODE_RTSPPUSH_OVER_UDP,	
	TESTMODE_UDP,	
	TESTMODE_MSAV,	
	TESTMODE_MSOSHLS,	
	TESTMODE_CONNECTTEST,	
	TESTMODE_ALL
}TESTMODE;


typedef struct TESTFUNCContex{
	ms_byte name[64];
	TESTMODE testmode;
	ms_u32 total_loop;
	ms_bool flag_iotest;
	ms_bool flag_302return;
	URLContext *pcilent_ctt_list;
	URLContext msusrctt_out;
	URLProtocol *msptl_in;
	URLProtocol *msptl_out;
	
	ms_s32 thread_index;
	
	ms_s32 test_index_start;
	ms_s32 test_index_end;
}TESTFUNCContex;

void testfunc_open(TESTFUNCContex * ptestfunc_txt,ms_bool flag_out)
{
	ms_s32 index;
	URLContext *pcilent_ctt=ms_null;
	for(index=ptestfunc_txt->test_index_start;index<ptestfunc_txt->test_index_end;index++){ 
		pcilent_ctt=&ptestfunc_txt->pcilent_ctt_list[index];
		if(ms_true==flag_out){
			pcilent_ctt->flags|=FLAG_WRITE;
		}else{
			if(0!=ptestfunc_txt->flag_302return){
				pcilent_ctt->opt.http.flag_302return=ms_true;
			}
			pcilent_ctt->flag_location=ms_false;
		}
		ptestfunc_txt->msptl_in->url_open(pcilent_ctt);
	}
}
void testfunc_io(TESTFUNCContex * ptestfunc_txt)
{
	ms_s32 index;
	URLContext *pcilent_ctt=ms_null;
	ms_u08 recvbuf[mscfg_maxlen_recv]={0};	/* buffer to receive data */
	ms_s32 numTest=ptestfunc_txt->test_index_end-ptestfunc_txt->test_index_start+1;
	ms_u64 curTime=mstime_api_us();
	ms_u64 baseTimeUs[(const ms_s32)numTest];
	ms_s32 indexBaseTime;
	while(1){
		for(index=ptestfunc_txt->test_index_start;index<ptestfunc_txt->test_index_end;index++){ 
			indexBaseTime=index-ptestfunc_txt->test_index_start;
			pcilent_ctt=&ptestfunc_txt->pcilent_ctt_list[index];
			ms_s32 len=ptestfunc_txt->msptl_in->url_read( pcilent_ctt, recvbuf, mscfg_maxlen_recv);
			if(len>0){
				baseTimeUs[indexBaseTime]=mstime_api_us();
				if(0==index){
					ptestfunc_txt->msptl_out->url_write(&ptestfunc_txt->msusrctt_out, recvbuf, len);
				}
			}else if(-3==len){
				ptestfunc_txt->msptl_in->url_close(pcilent_ctt);
				if(0!=ptestfunc_txt->flag_302return){
					pcilent_ctt->opt.http.flag_302return=ms_true;
				}
				pcilent_ctt->flag_location=ms_false;
				ptestfunc_txt->msptl_in->url_open(pcilent_ctt);
			}else{
				if(mstime_api_counterAsyncUs(&baseTimeUs[indexBaseTime], ms_usseconds(10))){
					ptestfunc_txt->msptl_in->url_close(pcilent_ctt);
					ptestfunc_txt->msptl_in->url_open(pcilent_ctt);
				}else{
					ms_usleep(50);
				}
			}
		}
	}
}
void testfunc_close(TESTFUNCContex * ptestfunc_txt)
{
	ms_s32 index;
	URLContext *pcilent_ctt=ms_null;
	for(index=ptestfunc_txt->test_index_start;index<ptestfunc_txt->test_index_end;index++){ 
		pcilent_ctt=&ptestfunc_txt->pcilent_ctt_list[index];
		ptestfunc_txt->msptl_in->url_close(pcilent_ctt);
	}
}
static ms_pvoid  test_func_noread(ms_void * ms_in arglist)
{
	TESTFUNCContex * ptestfunc_cxt=(TESTFUNCContex * )arglist;
	ms_s32 index;
	ms_info("[%s]---test_index(%d:%d)",ptestfunc_cxt->name,ptestfunc_cxt->test_index_start,ptestfunc_cxt->test_index_end);
ms_info("[%s]BN------------------------",ptestfunc_cxt->name);
		ms_info("[%s]OPEN BN------------------------",ptestfunc_cxt->name);
		if(TESTMODE_RTSPPUSH_OVER_UDP==ptestfunc_cxt->testmode){
			testfunc_open(ptestfunc_cxt,ms_true);
		}else{
			testfunc_open(ptestfunc_cxt,ms_false);
		}
		ms_info("[%s]OPEN EN------------------------",ptestfunc_cxt->name);
ms_info("[%s]EN------------------------",ptestfunc_cxt->name);
}
static ms_pvoid  test_func_nor(ms_void * ms_in arglist)
{
	TESTFUNCContex * ptestfunc_cxt=(TESTFUNCContex * )arglist;
	ms_s32 index;
	ms_info("[%s]---test_index(%d:%d)",ptestfunc_cxt->name,ptestfunc_cxt->test_index_start,ptestfunc_cxt->test_index_end);
	while(1)
	{
ms_info("[%s]BN------------------------",ptestfunc_cxt->name);
		ms_info("[%s]OPEN BN------------------------",ptestfunc_cxt->name);
		if(TESTMODE_RTSPPUSH_OVER_UDP==ptestfunc_cxt->testmode){
			testfunc_open(ptestfunc_cxt,ms_true);
		}else{
			testfunc_open(ptestfunc_cxt,ms_false);
		}
		ms_info("[%s]OPEN EN------------------------",ptestfunc_cxt->name);
		
		if(ms_true==ptestfunc_cxt->flag_iotest){
			testfunc_io(ptestfunc_cxt);
			ms_sleep(1);
		}else{
			ms_sleep(1);
		}
		
		ms_info("[%s]CLOSE BN------------------------",ptestfunc_cxt->name);
		testfunc_close(ptestfunc_cxt);
		ms_info("[%s]CLOSE EN------------------------",ptestfunc_cxt->name);

ms_info("[%s]EN------------------------",ptestfunc_cxt->name);
		
		ms_sleep(3);
		if((ptestfunc_cxt->total_loop>0) && ms_lessThan((--ptestfunc_cxt->total_loop), 1)){
			break;
		}
	}
}

static ms_pvoid  test_func(ms_void * ms_in arglist)
{
	TESTFUNCContex * ptestfunc_cxt=(TESTFUNCContex * )arglist;
#if 0	
	if(ms_true==ptestfunc_cxt->flag_iotest){
		if(1==ptestfunc_cxt->thread_index){
			test_func_noread(arglist);
		}else{
			test_func_nor(arglist);
		}
	}else{
		test_func_nor(arglist);
	}
#else
	test_func_nor(arglist);
#endif
}


int main(int argc, char **argv)
{
	mslog_api_init( 53, ms_null,ms_null, ms_null);
	if(argc==1){
		argv[1]="rtp://127.0.0.1:5000";
		argv[2]="127.0.0.1";
		argv[3]="20000";
		argv[4]="1500";
		argv[5]="52";
		argc=6;
	}
	if(argc<5){
		ms_error("Userage:%s urlin urlout_ip  urlout_port_start  num [logopt ] " ,argv[0]);
		return 0;
	}
	msthread_api_envInit();
	msthread_api_setName("mscore_utm");
	msmem_api_init(ms_false);
	msptc_api_init();
	msptc_api_register();
	msmd_api_setUlimit();
	
	ms_debug("Get param");
	ms_byte urlin[1024]={0};
	ms_strcpy(urlin, (argv[1]));
	ms_byte urlout_ip[256]={0};
	ms_strcpy(urlout_ip, (argv[2]));
	ms_s32 urlout_port_start=ms_atoi(argv[3]);
	ms_s32 num=ms_atoi(argv[4]);
	ms_s32 logopt=(6==argc) ? ms_atoi(argv[5]) : 51;
	
	mslog_api_init( logopt, ms_null,ms_null, ms_null);
	

//Get msptl_in	
	URLContext msusrctt_in;
	ms_memset(&msusrctt_in,0,sizeof(URLContext));
	ms_strcpy(msusrctt_in.url, urlin);
	URLProtocol *msptl_in=msptc_api_matchByUrl(urlin);	
	ms_debug("open:%s",msusrctt_in.url);
	msptl_in->url_open(&msusrctt_in);

//Get urlout
	URLContext *pcilent_ctt_list=ms_null;
	ms_malloc_retErr(-1,pcilent_ctt_list,(num*sizeof(URLContext)),"pcilent_ctt_list");
	ms_s32 index=0;
	URLContext *pcilent_ctt=ms_null;
	URLProtocol *msptl_out=msptc_api_matchByPtcindex(msptc_udp);
	for(index=0;index<num;index++){ 
		pcilent_ctt=&pcilent_ctt_list[index];
		ms_sprintfs(pcilent_ctt->url,"udp://%s:%d",urlout_ip,(urlout_port_start+index));
		pcilent_ctt->flags=FLAG_WRITE;
		ms_debug("open:%s",pcilent_ctt->url);
		msptl_out->url_open(pcilent_ctt);	
	}
	int recvlen=0;
	ms_byte buf[5120]={0};
	while(1){
		recvlen=msptl_in->url_read( &msusrctt_in, buf , 5120 );
		if(recvlen>0){
			for(index=0;index<num;index++){ 
				msptl_out->url_write(&pcilent_ctt_list[index], buf , recvlen );	
			}
		}
	}
end:	
	for(index=0;index<num;index++){ 
		msptl_out->url_close(&pcilent_ctt_list[index]);	
	}
	ms_deMalloc(pcilent_ctt_list);
	msthread_api_envDeinit();
	msptc_api_deinit();
	msmem_api_deinit();
	mslog_api_deinit();
}
#undef MAIN_C

